﻿using System;
using System.Collections.Generic;
using CookComputing.XmlRpc;
//
using PerceptiveMCAPI.Types;
using PerceptiveMCAPI.Types.Internal;
//
namespace PerceptiveMCAPI.Methods
{

	public abstract class Api_BaseExecute
	{
		protected bool ValidationIsOK { get; set; }
		protected Api_BaseInput Input { get; private set; }
		private string apikey { get; set; }
		private string datacenter { get; set; }
		private string SubmitUrl { get; set; }

		// private new Api_BaseInput Input { get; set; }
		// private Api_BaseOutput Output { get; set; }
		#region ================================================================= Main
		// =============================================== constructors
		//public method() { }
		//// ---------
		//public method( methodInput input ) { Input = input; }
		//// =============================================== Execute
		//public methodOutput Execute()
		//{
		//   // empty constructor & Execute() is bad
		//   if ( Input == null )
		//      throw new ArgumentException( "Input class not provided" );
		//   // do the deed
		//   Output = Execute( Input );
		//   return Output;
		//}
		//// ----------------------------------
		// public methodOutput Execute( methodInput input )
		//{
		//   Input = input;
		//   Output = new methodOutput( Input );
		//   ValidationIsOK = true;
		//   //------------------------- validate it
		//   if ( Input.api_Validate )
		//   {
		//      Output.api_ValidatorMessages = ValidateInput.Validate( Input );
		//      ValidationIsOK = ValidateInput.IsOK( Output.api_ValidatorMessages );
		//   }
		//   //------------------------- do it
		//   if ( ValidationIsOK )
		//   {
		//      ApiRun( Input, input.parms.apikey );  // execute API & format output
		//   }
		//   // ---
		//   return Output;
		//}
		#endregion

		#region ================================================================= API Calls
		// // ---------------------------------------------------------- XmlRpc
		protected abstract void ExecuteXmlRpc();
		//{
		//   try
		//   {
		//      XmlRpcStruct rpcResult = apiXmlRpc.api.campaignClickStats( Input.parms.apikey, Input.parms.cid );
		//      Output.Format( rpcResult );
		//   }
		// catch ( XmlRpcFaultException fex )
		// {
		//    Output.api_ErrorMessages.Add( apiException.FormatError( fex ) );
		// }
		// catch ( Exception ex )
		// {
		//    Output.api_ErrorMessages.Add( apiException.FormatError( ex ) );
		// }

		//}
		// // ---------------------------------------------------------- Serial Post
		protected abstract void ExecuteSerialPost();
		//{
		//  try
		//  {
		//   Dictionary<string, string> dict = new Dictionary<string, string>();
		//   dict.Add( "apikey", Input.parms.apikey );
		//   dict.Add( "cid", Input.parms.cid );
		//   dict.Add( "start", Input.parms.start.ToString() );
		//   dict.Add( "limit", Input.parms.limit.ToString() );
		//   // -- do it
		//   string api_Request = "";
		//   string api_Response = apiSerial.ProcessRequest( Input, dict, out api_Request );
		//   Output.Format( api_Request, api_Response );
		// }
		// catch ( Exception ex )
		// {
		//    Output.api_ErrorMessages.Add( apiException.FormatError( ex ) );
		// }
		//}
		#endregion

		#region ================================================================= virtuals

		// ----------------------------------------------- Run
		protected virtual void ApiRun( Api_BaseInput input, string apikey )
		{
			this.Input = input;
			this.apikey = apikey;
			//
			Input.SubmitUrl = FormatSubmitUrl();
			CheckForParmConflicts();
			// -----------------------------------------------------------
			EnumValues.AccessType accessType = Input.api_AccessType;
			switch ( accessType )
			{
				case EnumValues.AccessType.XmlRpc:
					CheckXmlRpcSettings();
					ExecuteXmlRpc();
					break;
				case EnumValues.AccessType.Serial:
					ExecuteSerialPost();
					break;
				case EnumValues.AccessType.JSON:
					throw new NotImplementedException( "JSON Input support is not currently provided. It WILL be soon." );
					break;
				default:
					throw new ArgumentException( "Invalid or missing parameter", "accessType" );
			}
		}

		// -------------------------------------------------------
		protected string FormatSubmitUrl()
		{
			string protocol = "http://";
			if ( Input.api_SecureAccess ) protocol = "https://";
			//
			if ( Input.api_DataCenter == "auto" ) datacenter = this.GetDataCenter( this.apikey );
			else datacenter = Input.api_DataCenter;
			//
			return string.Format( "{0}{1}.{2}", protocol, datacenter, MCAPISettings.api_URL );
		}

		// ----------------------------------------------------------------------------
		protected string GetDataCenter( string apikey )
		{
			string dc = "us1";   // default
			//---------------------------------------------
			// find the '-' and get the dc
			int dashix = apikey.LastIndexOf( "-" );
			if ( dashix > 0 )
			{
				dc = apikey.Substring( dashix + 1, 3 );
			}
			//
			return dc;
		}

		// ----------------------------------------------------------------------------
		protected void CheckXmlRpcSettings()
		{
			// check if settings for proxy need to be changed; if so, do it
			if ( apiXmlRpc.api.Timeout != Input.api_Timeout ||
				  apiXmlRpc.api.Url != this.SubmitUrl )
			{
				apiXmlRpc.CreateProxy( datacenter, Input.api_SecureAccess, Input.api_Timeout );
			}
		}
		// ----------------------------------------------------------------------------
		protected void CheckForParmConflicts()
		{
			// access type to output type
			if ( ( Input.api_AccessType == EnumValues.AccessType.XmlRpc && Input.api_OutputType != EnumValues.OutputType.XmlRpc )
				|| ( Input.api_AccessType == EnumValues.AccessType.JSON && Input.api_OutputType != EnumValues.OutputType.JSON )
				|| ( Input.api_AccessType == EnumValues.AccessType.Serial && Input.api_OutputType == EnumValues.OutputType.XmlRpc )
				|| ( Input.api_OutputType == EnumValues.OutputType.Unformatted )
				)
			{
				throw new ArgumentException(
					string.Format( "Access type to Output type mismatch: {0} -> {1}",
						Input.api_AccessType.ToString(), Input.api_OutputType.ToString() )
						);
			}
		}
		// ---------
		#endregion
	}
}